home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1992-05-29 | 18.8 KB | 383 lines | [TEXT/MEDT] |
- IMPLEMENTATION MODULE M2CA; (* HS 19.4.85 / 10.6.86 / 29.2.92; WH 9.5.85 / 27.6.85 *)
-
- FROM SYSTEM IMPORT WORD;
- FROM M2DA IMPORT
- WordSize, MaxInt, MaxDouble, ObjPtr, StrPtr, ParPtr, PDPtr,
- Standard, ObjClass, StrForm, PDesc, Object, ovflchk,
- notyp, undftyp, booltyp, chartyp, inttyp,
- bitstyp, dbltyp, realtyp, lrltyp, proctyp,
- stringtyp, addrtyp, bytetyp, wordtyp;
- FROM M2SA IMPORT
- Mark;
- FROM M2HA IMPORT
- D0, D1, SB, MP, SP,
- byte, word, long,
- Condition, RegType, Register, WidType, ItemMode, Item,
- LongVal, WordVal, SimpleT, RealT,
- GetReg, Release, ReleaseReg, SetbusyReg, SaveRegs, RestoreRegs,
- SetlocMd, SetregMd, SetstkMd, SetconMd,
- StackTop, SetupSL, GenHalt,
- LoadD, LoadP, LoadX, Move, MoveAdr, MoveBlock, Tst1, Add2, Cmp2,
- CheckClimit, CheckRange, DynArray,
- Jf, Jb, EnterCase, ExitCase, Link, Unlink, CallInt, CallExt, CallInd,
- EnterModule, ExitModule, InitModule,
- FMove, LoadF, FMonad;
- FROM M2LA IMPORT
- pc, maxP, maxM, PutWord, AllocChar, FixLink, FixLinkWith, fixup;
- FROM M2EA IMPORT
- GlbParStartAdr, LocParStartAdr;
-
- VAR sp0, sp : INTEGER;
-
-
- PROCEDURE err(n: INTEGER);
- (* local synonym for M2SM.Mark to save space! *)
- BEGIN
- Mark(n);
- END err;
-
- PROCEDURE Put16(w : WORD);
- (* local synonym for M2LM.PutWord to save space! *)
- BEGIN
- PutWord(w);
- END Put16;
-
- PROCEDURE SRTest(VAR x : Item);
- BEGIN
- WITH x DO
- WHILE typ^.form = Range DO typ := typ^.RBaseTyp END;
- END (*WITH*);
- END SRTest;
-
- PROCEDURE setCC(VAR x : Item; fcc : Condition);
- (* transform all modes to 'cocMd' : *)
- BEGIN
- Release(x);
- WITH x DO
- typ := booltyp; mode := cocMd; CC := fcc;
- Tjmp := 0; Fjmp := 0;
- END;
- END setCC;
-
- PROCEDURE GenAssign(VAR x, y : Item);
- (* x := y *)
- (* y ---->> x *)
- (* or g ---->> f *)
- VAR f, g : StrForm;
- xp, yp : ParPtr;
- x0, y0 : Item;
- s, sadr : INTEGER;
- Min, Max : INTEGER;
- L : INTEGER;
- sz : WidType;
- xt : StrPtr;
- BEGIN
- IF (x.mode = conMd) OR (x.mode > stkMd) THEN err(134) END;
- SRTest(y);
- f := x.typ^.form;
- g := y.typ^.form;
- xt := x.typ; (* hold original type of x *)
- IF f = Range THEN
- (* perform range check. *)
- Min := x.typ^.min; Max := x.typ^.max;
- IF y.mode = conMd THEN
- IF (LongVal(y) < LONG(Min)) OR (LongVal(y) > LONG(Max)) THEN
- err(138)
- END
- ELSE
- CheckRange(y, Min, Max, 0)
- END;
- x.typ := x.typ^.RBaseTyp;
- f := x.typ^.form;
- END (*Range*);
-
- CASE f (* destination form *) OF
-
- Undef : err(133);
-
- | Byte : IF y.typ^.size = 1 THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Bool : IF g = Bool THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Char : IF g = Char THEN Move(y,x)
- ELSIF g = Byte THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Int : IF g = Int THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Enum : IF x.typ = y.typ THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Word : IF y.typ^.size = 2 THEN Move(y,x)
- ELSE err(133)
- END;
-
- | LWord : IF g = LWord THEN Move(y,x)
- ELSIF g = Double (* double constants *) THEN Move(y,x)
- ELSIF (x.typ = addrtyp) & (g = Pointer) THEN Move(y,x)
- ELSIF g = Int THEN
- IF y.mode = conMd THEN
- SetconMd(y, LongVal(y), xt);
- ELSE
- LoadX(y,long); y.typ := xt;
- END;
- Move(y,x)
- ELSE err(133)
- END;
-
- | Double : IF g = Double THEN Move(y,x)
- ELSIF g = Int THEN
- IF y.mode = conMd THEN
- SetconMd(y, LongVal(y), xt);
- ELSE
- LoadX(y,long); y.typ := xt;
- END;
- Move(y,x)
- ELSE err(133)
- END;
-
- | Real : IF g = Real THEN FMove(y,x)
- ELSE err(133)
- END;
-
- | LongReal : IF g = LongReal THEN FMove(y,x)
- ELSIF g = Real THEN
- FMonad(Long,y);
- y.typ := xt;
- FMove(y,x)
- ELSE err(133)
- END;
-
- | Pointer : IF (x.typ = y.typ) OR (y.typ = addrtyp) THEN
- Move(y,x)
- ELSE err(133)
- END;
-
- | Set : IF x.typ = y.typ THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Opaque : IF (x.typ = y.typ) THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Record : IF x.typ = y.typ THEN
- s := x.typ^.size;
- MoveBlock(y,x,s,FALSE)
- ELSE err(133)
- END;
-
- | ProcTyp : IF y.mode = procMd THEN
- (* procedure-constant to procedure-variable : *)
- IF y.proc^.pd^.lev # 0 THEN err(127)
- ELSIF x.typ^.resTyp # y.proc^.typ THEN err(128)
- ELSE xp := x.typ^.firstPar; yp := y.proc^.firstParam;
- WHILE xp # NIL DO
- IF yp # NIL THEN
- IF (xp^.varpar # yp^.varpar) OR
- ((xp^.typ # yp^.typ) AND
- ((xp^.typ^.form # Array) OR
- NOT xp^.typ^.dyn OR
- (yp^.typ^.form # Array) OR
- NOT yp^.typ^.dyn OR
- (xp^.typ^.ElemTyp # yp^.typ^.ElemTyp))) THEN
- err(129)
- END;
- yp := yp^.next
- ELSE err(130)
- END;
- xp := xp^.next
- END (*WHILE*);
- IF yp # NIL THEN err(131) END;
- MoveAdr(y,x);
- END;
- ELSIF x.typ = y.typ THEN Move(y,x)
- ELSE err(133)
- END;
-
- | Array : s := x.typ^.size;
- IF (x.typ = y.typ) & NOT(x.typ^.dyn) THEN
- MoveBlock(y,x,s,FALSE)
- ELSIF (x.mode = stkMd) & x.typ^.dyn THEN
- (* formal parameter is dynamic array : *)
- IF (g = Array) & (x.typ^.ElemTyp = y.typ^.ElemTyp) THEN
- DynArray(x,y)
- ELSE
- IF (x.typ^.ElemTyp = chartyp) OR
- (x.typ^.ElemTyp = bytetyp) THEN
- IF g = String THEN
- DynArray(x,y)
- ELSIF (g = Char) & (y.mode = conMd) THEN
- (* character-constant to dynamic array : *)
- AllocChar(y.val.Ch, sadr);
- WITH y DO
- typ := stringtyp; val.D0 := sadr; val.D1 := 2;
- END (*WITH*);
- DynArray(x,y)
- ELSIF (x.typ^.ElemTyp = bytetyp) THEN DynArray(x,y)
- ELSE err(133)
- END
- ELSE err(133)
- END
- END
- ELSIF (x.typ^.ElemTyp = chartyp) THEN
- IF x.typ^.dyn THEN err(143) END;
- IF x.typ^.IndexTyp # NIL THEN
- WITH x.typ^.IndexTyp^ DO
- IF form = Range THEN s := max - min + 1 END;
- END;
- END;
- IF g = String THEN
- (* string to fixed-size array : 4th edition *)
- (* length of string must be less than that of array! *)
- IF y.val.D1 > s THEN err(146) END;
- MoveBlock(y,x,s,TRUE);
- ELSIF (g = Char) & (y.mode = conMd) THEN
- (* character-constant to fixed-size array : *)
- AllocChar(y.val.Ch, sadr);
- WITH y DO
- typ := stringtyp; val.D0 := sadr; val.D1 := 2;
- END (*WITH*);
- IF s < 2 THEN err(146) END;
- MoveBlock(y,x,s,TRUE);
- ELSE err(133)
- END
- ELSE err(133)
- END;
-
- ELSE (* must not occur on the left side *)
- err(133)
- END (*CASE f*);
- x.typ := xt; (* restore original type of x *)
- Release(y);
- Release(x);
- END GenAssign;
-
- PROCEDURE GenFJ(VAR loc: INTEGER);
- BEGIN
- Jf(T, loc);
- END GenFJ;
-
- PROCEDURE GenCFJ(VAR x: Item; VAR loc: INTEGER);
- BEGIN
- IF x.typ = booltyp THEN
- IF x.mode # cocMd THEN Tst1(x); setCC(x, EQ) END;
- ELSE
- setCC(x, EQ); err(135); (* type of expression must be boolean *)
- END;
- loc := x.Fjmp; Jf(x.CC, loc); FixLink(x.Tjmp);
- END GenCFJ;
-
- PROCEDURE GenBJ(loc: INTEGER);
- BEGIN
- Jb(T, loc);
- END GenBJ;
-
- PROCEDURE GenCBJ(VAR x: Item; loc: INTEGER);
- BEGIN
- IF x.typ = booltyp THEN
- IF x.mode # cocMd THEN Tst1(x); setCC(x, EQ) END;
- ELSE
- setCC(x, EQ); err(135); (* type of expression must be boolean *)
- END;
- Jb(x.CC, loc); FixLinkWith(x.Fjmp, loc); FixLink(x.Tjmp);
- END GenCBJ;
-
- PROCEDURE SpaceForFunction(func : StrPtr);
- (* reserve space on top of stack for function result. *)
- VAR tos : Item;
- BEGIN
- SetstkMd(tos, func);
- IF SimpleT(tos) OR RealT(tos) OR (func^.size IN {1,2,4,8}) THEN
- StackTop( - func^.size )
- ELSE
- err(200)
- END;
- END SpaceForFunction;
-
- PROCEDURE PrepCall(VAR x: Item; VAR fp: ParPtr; VAR regs: LONGINT);
- VAR func: StrPtr; Rn: Register;
- BEGIN
- Rn := 0;
- WITH x DO
- IF (mode = procMd) OR (mode = codMd) THEN
- func := proc^.typ; fp := proc^.firstParam;
- ELSIF typ^.form = ProcTyp THEN
- func := typ^.resTyp; fp := typ^.firstPar;
- LoadP(x); (* load procedure variable *)
- Rn := R; ReleaseReg(Rn); (* inhibit save of register Rn *)
- ELSE
- func := notyp; fp := NIL;
- err(136); (* call of an object which is not a procedure *)
- END;
- SaveRegs(regs);
- IF Rn # 0 THEN SetbusyReg(Rn) END; (* re-reserve register Rn *)
- IF func # notyp THEN SpaceForFunction(func) END;
- END (*WITH*);
- END PrepCall;
-
- PROCEDURE GenParam(VAR ap: Item; f: ParPtr);
- VAR fp: Item;
- BEGIN
- SetstkMd(fp, f^.typ);
- IF f^.varpar THEN
- IF (fp.typ^.form = Array) & fp.typ^.dyn & (fp.typ^.ElemTyp = bytetyp) THEN
- DynArray(fp, ap);
- ELSIF (fp.typ^.form = Array) & fp.typ^.dyn &
- (ap.typ^.form = Array) & (ap.typ^.ElemTyp = fp.typ^.ElemTyp) THEN
- DynArray(fp, ap);
- ELSIF (ap.typ = fp.typ) OR
- (fp.typ = wordtyp) & (ap.typ^.size = 2) OR
- (fp.typ = bytetyp) & (ap.typ^.size = 1) OR
- (fp.typ = addrtyp) & (ap.typ^.form = Pointer) THEN
- IF (ap.mode = procMd) & (f^.typ^.form # ProcTyp) THEN
- err(137)
- ELSE
- MoveAdr(ap, fp)
- END;
- ELSE
- err(137); (* type of VAR par is not identical to that of actual par *)
- END;
- ELSE
- GenAssign(fp, ap); (* type check in GenAssign *)
- END;
- Release(ap);
- END GenParam;
-
- PROCEDURE RestoreResultAndRegs(VAR x : Item; regs : LONGINT);
- VAR y, z : Item; sz : INTEGER;
- BEGIN
- WITH x DO
- SetstkMd(x, typ); (* result on top of stack *)
- IF regs # 0D THEN (* saved registers above result *)
- (* Caution: saved registers remain busy, so the LoadD(x) *)
- (* ------- below gets a pool-register which is NOT in *)
- (* the set of the registers to be restored. *)
- IF SimpleT(x) THEN LoadD(x)
- ELSIF RealT(x) THEN LoadF(x)
- ELSE (* structured type *)
- sz := typ^.size;
- IF NOT(sz IN {1,2,4,8}) THEN
- err(200); (* function result size not implemented! *)
- ELSE
- IF sz IN {1,2,4} THEN (* byte/word/long result *)
- SetstkMd(z, typ);
- SetregMd(y, D0, typ); Move(z,y);
- RestoreRegs(regs); regs := 0D;
- Move(y,z);
- ELSE (* double-longword result *)
- SetstkMd(z, dbltyp);
- SetregMd(y, D0, dbltyp); Move(z,y);
- SetregMd(y, D1, dbltyp); Move(z,y);
- RestoreRegs(regs); regs := 0D;
- SetregMd(y, D1, dbltyp); Move(y,z);
- SetregMd(y, D0, dbltyp); Move(y,z);
- EN